home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / prof / sun4c.md / profSubr.c < prev   
C/C++ Source or Header  |  1991-05-30  |  11KB  |  449 lines

  1. /* 
  2.  * prof.c --
  3.  *
  4.  *    Routines for initializing and collecting profile information.
  5.  *
  6.  * Copyright 1985 Regents of the University of California
  7.  * All rights reserved.
  8.  */
  9.  
  10. #ifndef lint
  11. static char rcsid[] = "$Header: /sprite/src/kernel/prof/sun4.md/RCS/profSubr.c,v 1.5 91/05/30 15:17:20 kupfer Exp $ SPRITE (Berkeley)";
  12. #endif
  13.  
  14. #define MCOUNT
  15.  
  16. #include <sprite.h>
  17. #include <stdio.h>
  18. #include <prof.h>
  19. #include <profInt.h>
  20. #include <dbg.h>
  21. #include <sys.h>
  22. #include <timer.h>
  23. #include <mach.h>
  24. #include <fs.h>
  25. #include <vm.h>
  26. #include <bstring.h>
  27.  
  28. extern    int    etext;
  29.  
  30. /*
  31.  * An on/off profiling switch.
  32.  */
  33.  
  34. Boolean profEnabled = FALSE;
  35.  
  36. Address savedStackPtr;
  37.  
  38. /*
  39.  * A histogram of PC samples is kept for use by gprof. Each sample is a
  40.  * counter that gets incremented when the PC is in the range for the counter.
  41.  */
  42.  
  43. typedef struct {
  44.     Address lowpc;
  45.     Address highpc;
  46.     int        size;
  47. } SampleHdr;
  48.  
  49. static int    pcSampleSize;
  50. static short    *pcSamples;
  51.  
  52. /*
  53.  * PC sampling data structures (shared with _mcount.c).
  54.  */
  55.  
  56. int        profArcListSize;
  57. ProfRawArc    *profArcList;
  58. ProfRawArc    *profArcListFreePtr;
  59. ProfRawArc    *profArcListEndPtr;
  60.  
  61. int        profArcIndexSize;
  62. ProfRawArc    **profArcIndex;
  63.  
  64. /*
  65.  * Flag to indicate if Prof_Init has been called.
  66.  */
  67. static Boolean    init = FALSE;
  68.  
  69.  
  70. /*
  71.  *----------------------------------------------------------------------
  72.  *
  73.  * Prof_Init --
  74.  *
  75.  *    Allocate the profile data structures and initialize the profile timer.
  76.  *    The timer is initialized to automatically start ticking again
  77.  *    once its interrupt line is reset.  The array of counters
  78.  *    for sampling the PC is allocated, as is the table of call
  79.  *    graph arc counts.
  80.  *
  81.  * Results:
  82.  *    None.
  83.  *
  84.  * Side effects:
  85.  *    Uses Vm_RawAlloc.  Each structure is order(textSize).
  86.  *    Sets a flag indicating it has been called.
  87.  *
  88.  *----------------------------------------------------------------------
  89.  */
  90.  
  91. void
  92. Prof_Init()
  93. {
  94.     int numInstructions;
  95.  
  96.     /*
  97.      * We estimate the number of instructions in the text
  98.      * by dividing the address range by four...  This determines
  99.      * to PC to index calculations done in mcount and Prof_CollectInfo.
  100.      */
  101.  
  102.     numInstructions = ((unsigned)&etext - (unsigned)&spriteStart) >>
  103.                             PROF_INSTR_SIZE_SHIFT;
  104.     printf("Prof_Init: # instructions in kernel = %d\n", numInstructions);
  105.  
  106.     /*
  107.      * The size of the sample array reflects a compression down
  108.      * by the group size.
  109.      */
  110.  
  111.     pcSampleSize = numInstructions / PROF_PC_GROUP_SIZE;
  112.     pcSamples = (short *) Vm_RawAlloc(pcSampleSize * sizeof(short));
  113.  
  114.     /*
  115.      * Allocate an array indexed by PC and containing a pointer
  116.      * to the call graph arc that starts at that PC.  This array is
  117.      * compressed by the arc group size.
  118.      */
  119.     profArcIndexSize = numInstructions >> PROF_ARC_GROUP_SHIFT;
  120. #ifdef MCOUNT
  121.     profArcIndex = 
  122.     (ProfRawArc **) Vm_RawAlloc(profArcIndexSize * sizeof(ProfRawArc *));
  123. #endif /* MCOUNT */
  124.  
  125.     /*
  126.      * The arcList needs an element for every distinct call instruction
  127.      * that gets executed in the kernel.  The size is just a guess.
  128.      */
  129.  
  130.     profArcListSize = numInstructions / PROF_CALL_RATIO;
  131. #ifdef MCOUNT
  132.     profArcList = 
  133.         (ProfRawArc *) Vm_RawAlloc(profArcListSize * sizeof(ProfRawArc));
  134. #endif /* MCOUNT */
  135.  
  136.     init = TRUE;
  137. }
  138.  
  139. /*
  140.  *----------------------------------------------------------------------
  141.  *
  142.  * Prof_Start --
  143.  *
  144.  *    Initialize the profile data structures and the profile timer.
  145.  *    This clears the PC sample counters, the call graph arc counters,
  146.  *    and the index into the list of call graph arc counters.
  147.  *
  148.  *    The interval between profile timer interrupts is defined in the
  149.  *    timer module.
  150.  *
  151.  * Results:
  152.  *    Return status.
  153.  *
  154.  * Side effects:
  155.  *    Profiling is enabled and the data structures are zeroed.
  156.  *
  157.  *----------------------------------------------------------------------
  158.  */
  159.  
  160. ReturnStatus
  161. Prof_Start()
  162. {
  163.     if (!init) {
  164.     Prof_Init();
  165.     }
  166.  
  167.     printf("Starting Profiling...");
  168.  
  169.     /*
  170.      * Reset the PC sample counters.
  171.      */
  172.  
  173.     bzero((Address) pcSamples, pcSampleSize * sizeof(short));
  174.  
  175. #ifdef MCOUNT
  176.     /*
  177.      * Reset the arc pointer list indexed by caller PC.
  178.      */
  179.  
  180.     bzero((Address) profArcIndex, profArcIndexSize * sizeof(ProfRawArc *));
  181.  
  182.     /*
  183.      * Set the free pointers into the arc storage.  Don't have to
  184.      * initialize the arc storage itself because that is done
  185.      * as arc storage is allocated by mcount.
  186.      */
  187.  
  188.     profArcListFreePtr = &profArcList[0];
  189.     profArcListEndPtr = &profArcList[profArcListSize-1];
  190. #endif /* MCOUNT */
  191.  
  192.     Timer_TimerInit(TIMER_PROFILE_TIMER);
  193.     Timer_TimerStart(TIMER_PROFILE_TIMER);
  194.  
  195.     profEnabled = TRUE;
  196.     printf(" done\n");
  197.     return(SUCCESS);
  198. }
  199.  
  200.  
  201. /*
  202.  *----------------------------------------------------------------------
  203.  *
  204.  * Prof_CollectInfo --
  205.  *
  206.  *    Collect profiling information from the stack.
  207.  *    Look at the Status register to make sure we are
  208.  *    running in the kernel, then sample the PC.
  209.  *
  210.  *    The interval between calls to this routine is defined
  211.  *    by the profile timer's interrupt interval, which is
  212.  *    defined in devTimer.c.
  213.  *
  214.  *    Note: This is an interrupt-level routine.
  215.  *
  216.  * Results:
  217.  *    None.
  218.  *
  219.  * Side effects:
  220.  *    Increment the counter associated with the PC value.
  221.  *
  222.  *----------------------------------------------------------------------
  223.  */
  224.  
  225. #ifdef NOTDEF
  226. void
  227. Prof_CollectInfo(stackPtr)
  228.     Mach_IntrStack    *stackPtr;
  229. {
  230.     if (!profEnabled) {
  231.     return;
  232.     }
  233.     if (stackPtr->excStack.statusReg & MACH_SR_SUPSTATE) {
  234.     register unsinged int pc;    /* The program counter. */
  235.     register int index;    /* Index into the array of counters */
  236.  
  237.     pc = stackPtr->excStack.pc;
  238. #else
  239. void
  240. Prof_CollectInfo(pc)
  241.     register unsigned int pc;
  242. {
  243.     register int    index;
  244.  
  245.     if (!profEnabled) {
  246.     return;
  247.     }
  248. #endif
  249.     if (pc >= (unsigned int) &spriteStart && pc <= (unsigned int) &etext) {
  250.     index = (pc - (unsigned int) &spriteStart) >> PROF_PC_SHIFT;
  251.     if (index < pcSampleSize) {
  252.         pcSamples[index]++;
  253.     }
  254.     }
  255. }
  256.  
  257.  
  258. /*
  259.  *----------------------------------------------------------------------
  260.  *
  261.  * Prof_End --
  262.  *
  263.  *    Stop the profiling.
  264.  *
  265.  * Results:
  266.  *    Return status.
  267.  *
  268.  * Side effects:
  269.  *    Profiling is disabled.
  270.  *
  271.  *----------------------------------------------------------------------
  272.  */
  273.  
  274. ReturnStatus
  275. Prof_End()
  276. {
  277.     Timer_TimerInactivate(TIMER_PROFILE_TIMER);
  278.     profEnabled = FALSE;
  279.     return(SUCCESS);
  280. }    
  281.  
  282. /*
  283.  *----------------------------------------------------------------------
  284.  *
  285.  * Prof_Dump --
  286.  *
  287.  *    Dump out the profiling data to the specified file.
  288.  *
  289.  * Results:
  290.  *    SUCCESS        - the information was dumped to the file.
  291.  *    ?        - return codes from Fs module.
  292.  *
  293.  * Side effects:
  294.  *    Write the profiling data to a file.
  295.  *
  296.  *----------------------------------------------------------------------
  297.  */
  298.  
  299. ReturnStatus
  300. Prof_Dump(dumpName)
  301.     char *dumpName;        /* Name of the file to dump to. */
  302. {
  303.     ReturnStatus    status;
  304.     Fs_Stream        *streamPtr;
  305.     int            fileOffset;
  306.     int            writeLen;
  307. #ifdef MCOUNT
  308.     int            index;
  309.     ProfArc        arc;
  310.     ProfRawArc        *rawArcPtr;
  311. #endif
  312.     SampleHdr        sampleHdr;
  313.  
  314.     status = Fs_Open(dumpName, FS_WRITE|FS_CREATE|FS_TRUNC, FS_FILE,
  315.         0666, &streamPtr);
  316.     if (streamPtr == (Fs_Stream *) NIL || status != SUCCESS) {
  317.     return(status);
  318.     }
  319.  
  320.     /*
  321.      * Write out the PC sampling counters.  Note they are preceeded
  322.      * by a header that indicates the PC range and the size of the
  323.      * sampling buffer.  (The size includes the header size...)
  324.      */
  325.  
  326.     sampleHdr.lowpc    = (Address) &spriteStart;
  327.     sampleHdr.highpc    = (Address) &etext;
  328.     sampleHdr.size    = (pcSampleSize * sizeof(short)) + sizeof(sampleHdr);
  329.  
  330.     fileOffset = 0;
  331.     writeLen = sizeof(sampleHdr);
  332.     status = Fs_Write(streamPtr, (Address) &sampleHdr, fileOffset, &writeLen);
  333.     if (status != SUCCESS) {
  334.     printf(
  335.             "Prof_Dump: Fs_Write(1) failed, status = %x\n",status);
  336.     goto dumpError;
  337.     }
  338.     printf("Prof_Dump: pc sample size = %d\n", pcSampleSize);
  339.  
  340.     fileOffset += writeLen;
  341.     writeLen = pcSampleSize * sizeof(short);
  342.     status = Fs_Write(streamPtr, (Address) pcSamples, fileOffset, &writeLen);
  343.     if (status != SUCCESS) {
  344.     printf(
  345.             "Prof_Dump: Fs_Write(2) failed, status = %x\n",status);
  346.     goto dumpError;
  347.     }
  348.  
  349.     fileOffset += writeLen;
  350.  
  351.     /*
  352.      * Write out instantiated arcs.  Loop through the arcIndex index
  353.      * and for each one that has arc storage figure out the PC that
  354.      * corresponds to the arcIndex.  Then dump out an entry for
  355.      * each routine called from that PC.
  356.      */
  357.  
  358. #ifdef MCOUNT
  359.     for (index = 0 ; index < profArcIndexSize ; index++) {
  360.     rawArcPtr = profArcIndex[index];
  361.  
  362.     /* 
  363.      * Check if rawArcPtr equals an unused value (which is 0 because 
  364.      * profArcIndex is initialized with bzero in Prof_Start).
  365.      */
  366.     if (rawArcPtr == (ProfRawArc *) 0) {
  367.         continue;
  368.     }
  369.  
  370.     /*
  371.      * Reverse the PC to index calculation done in mcount.
  372.      */
  373.     arc.callerPC = (int)&spriteStart + (index << PROF_ARC_SHIFT);
  374.  
  375.     do {
  376.         arc.calleePC = rawArcPtr->calleePC;
  377.         arc.count = rawArcPtr->count;
  378.  
  379.         writeLen = sizeof(ProfArc);
  380.         status = Fs_Write(streamPtr, (Address)&arc, fileOffset, &writeLen);
  381.         if (status != SUCCESS) {
  382.         printf(
  383.             "Prof_Dump: Fs_Write(3) failed, status = %x, index = %d\n",
  384.             status, index);
  385.         goto dumpError;
  386.         }
  387.         fileOffset += writeLen;
  388.  
  389.         rawArcPtr = rawArcPtr->link;
  390.         /*
  391.          * Check against NIL pointer here because of initialization
  392.          * in mcount.
  393.          */
  394.     } while (rawArcPtr != (ProfRawArc *)NIL);
  395.     }
  396. #endif /* MCOUNT */
  397.  
  398.     status = Fs_Close(streamPtr);
  399.     if (status != SUCCESS) {
  400.     printf(
  401.         "Prof_Dump: Fs_Close failed, status = %x\n", status);
  402.     }
  403.     return(status);
  404.  
  405. dumpError:
  406.     (void) Fs_Close(streamPtr);
  407.     return(status);
  408. }
  409.  
  410.  
  411. /*
  412.  *----------------------------------------------------------------------
  413.  *
  414.  * Prof_DumpStub --
  415.  *
  416.  *    This system call dumps profiling information into the specified file.
  417.  *    This is done by making the name of the file accessible, then calling 
  418.  *    Prof_Dump.
  419.  *
  420.  * Results:
  421.  *    SUCCESS        - the file was dumped.
  422.  *    ?        - error returned by Fs module.
  423.  *
  424.  * Side effects:
  425.  *    A file is written.
  426.  *
  427.  *----------------------------------------------------------------------
  428.  */
  429.  
  430. ReturnStatus
  431. Prof_DumpStub(pathName)
  432.     char *pathName;        /* The name of the file to write. */
  433. {
  434.     char    newName[FS_MAX_PATH_NAME_LENGTH];
  435.     int        pathNameLength;
  436.  
  437.     /*
  438.      * Copy the name in from user space to the kernel stack.
  439.      */
  440.     if (Proc_StringNCopy(FS_MAX_PATH_NAME_LENGTH, pathName, newName,
  441.              &pathNameLength) != SUCCESS) {
  442.     return(SYS_ARG_NOACCESS);
  443.     }
  444.     if (pathNameLength == FS_MAX_PATH_NAME_LENGTH) {
  445.     return(FS_INVALID_ARG);
  446.     }
  447.     return(Prof_Dump(newName));
  448. }
  449.